<?php

namespace Module\Admin;

use W3\Json;
use Manager\Options as Manager;
use W3\Plugin as Plugins;
use W3\Html;
use W3\Exception;

!defined('W3_ROOT_DIR') AND exit;

/**
 * 插件管理组件
 *
 * @author edikud
 * @date 2022/10/22
 * @copyright Copyright (c) 2022 W3 (http://www.mcooo.com)
 * @license GNU General Public License 2.0
 */
class Plugin extends Manager
{
    /**
     * 初始化
     *
     * @access protected
     * @return void
     */
    protected function init()
    {
		# 定义变量默认数据
        $this->parameter([

			# 设置主体
			'main' => 'admin.plugin',	
			
		], true);		
		
		# 必须为管理员以上权限
		$this->auth->check('admin');

	}
	
    /**
     * 绑定动作
     *
     * @access public
     * @return void
     */
    public function action()
    {
		$this->on(!$this->request->action || $this->request->is('action=index'))->index();
		$this->on($this->request->isGet() && $this->request->is('action=config'))->_config();
		$this->on($this->request->isPost() && $this->request->is('action=config'))->configSave();		
		$this->on($this->request->is('action=activate'))->activate();	
		$this->on($this->request->is('action=deactivate'))->deactivate();	
    }

    public function index()
    {
		/** 输出内容 */
		$this->layout->set($this->pluginsList(), 'body');

		$this->view();
    }

    public function pluginsList()
    {
		$this->widget('Plugin\Rows@activated', 'activated=1')->to($activatedPlugins);
		$html = '';
		
        if ($activatedPlugins->have() || !empty($activatedPlugins->activatedPlugins)) {
			
			$table = Html::table();
			
			$table->preppend('<h2>'.__('启用的插件').'</h2>');
			$table->thead->preppend('
                <colgroup>
				    <col width="30%" />
					<col width="40%" />
                    <col width="15%" />
					<col width="15%" />
                </colgroup>
			');
			$table->head([
			        __('名称'),
					__('描述'),
				    __('作者'),
				    __('操作')
			]);
			while ($activatedPlugins->next()){

			    $table->body([
				
				    $activatedPlugins->name . '<p class="badge badge-md badge-pill badge-primary-soft ml-2">v' . $activatedPlugins->version . '</p>',
					
				    $activatedPlugins->description . (!$activatedPlugins->dependence ? '<p class="badge badge-pill badge-danger-soft ml-2">' .__('版本检测不通过, 插件可能无法正常工作', [$activatedPlugins->name]). '</p>' : ''),
					
					empty($activatedPlugins->homepage) ? $activatedPlugins->author : '<a href="' . $activatedPlugins->homepage . '">' . $activatedPlugins->author . '</a>',
					
					($activatedPlugins->config ? Html::a($this->adminUrl('plugin/config', false) . '?name=' . $activatedPlugins->name, __('设置'))->addClass('btn btn-primary btn-sm mb-1') : '') . 
					Html::a($this->adminUrl('plugin/deactivate', false) . '?name=' . $activatedPlugins->name, __('禁用'))->addClass('deactivate btn btn-primary btn-sm mb-1')->data('confirm', __('你确认要禁用插件 %s 吗?', [$activatedPlugins->name]))

				]);
			}

            if (!empty($activatedPlugins->activatedPlugins)){
                foreach ($activatedPlugins->activatedPlugins as $key => $val){

                    $table->body([
					    $key,
					    '<p class="text-muted">' . __('此插件文件已经损坏或者被不安全移除, 强烈建议你禁用它'). '</p>',
						'',
						Html::a($this->adminUrl('plugin/deactivate', false) . '?name=' . $key, __('禁用'))->addClass('deactivate btn btn-primary btn-sm')->data('confirm', __('你确认要禁用插件 %s 吗?', [$key]))
					
					]);
                }
            } 
			$html .= $table->render();
		}

        $this->widget('Plugin\Rows@unactivated', 'activated=0')->to($disabledPlugins);
        if ($disabledPlugins->have() || !$activatedPlugins->have()){
			$table = Html::table();
			$table->preppend('<h2 style="margin-top:50px;">'.__('禁用的插件').'</h2>');
			$table->thead->preppend('
                <colgroup>
				    <col width="30%" />
					<col width="40%" />
                    <col width="15%" />
					<col width="15%" />
                </colgroup>
			');
            if ($disabledPlugins->have()){
			    $table->head([
			        __('名称'),
					__('描述'),
				    __('作者'),
				    __('操作')
			    ]);	

                while ($disabledPlugins->next()){

			        $table->body([
				        $disabledPlugins->name . '<p class="badge badge-md badge-pill badge-primary-soft ml-2">v' . $disabledPlugins->version . '</p>',
						
						$disabledPlugins->description,
						
					    empty($disabledPlugins->homepage) ? $disabledPlugins->author : '<a href="' . $disabledPlugins->homepage . '">' . $disabledPlugins->author . '</a>',
						
						Html::a($this->adminUrl('plugin/activate', false) . '?name=' . $disabledPlugins->name, __('启用'))->addClass('activate btn btn-primary btn-sm')
				    ]);
                }
            } else{
			    $table->append('<h6>'.__('没有安装插件').'</h6>');
            }
            $html .= $table->render();
		}

		return $html;
	}

    /**
     * 启用插件
     *
     * @throws Exception
     */
    public function activate()
    {
		$pluginName = $this->request->filter('strip_tags')->name;
		$className = Plugins::getName($pluginName);
		$file      = Plugins::getFile($pluginName);

        /** 判断插件是否存在 */
        if(empty($file)){
			throw new Exception(__('插件不存在, 无法启用'));
        }		

        $info = Plugins::getInfo($file);

        /** 检测依赖信息 */
        if (Plugins::version($this->config->version, $info['dependence'])) {

            /** 判断启用是否成功 */
            if (Plugins::exists($pluginName)) {
				
				$this->notice(__('插件已启用'), 'notice');
				$this->goBack();
            }

            /** 载入插件 */
            require_once $file;

            /** 检查类是否已定义 || 检查类的方法是否存在 */
            if (!class_exists($className) || !method_exists($className, 'activate')) {
				
				$this->notice(__('无法启用插件'), 'error');
				$this->goBack();
            }

            try {
                $result = call_user_func([$className, 'activate']);
                Plugins::activate($pluginName);
                $this->updateOptions('plugins', Plugins::export());

            } catch (\Exception $e) {
				
                /** 截获异常 */
				$this->notice($e->getMessage(), 'error');
				$this->goBack();
            }

            $form = Html::form();
            call_user_func([$className, 'config'], $form);

            $options = $form->values();

            if ($options) {
                $this->configPlugin($pluginName, $options);
            }
        } else {
            $result = __('<a href="%s">%s</a> 无法在此版本的W3下正常工作', [$info['homepage'], $info['title']]);
        }

        if (isset($result) && is_string($result)) {
            $this->notice($result);
        } else {
            $this->notice(__('启用成功'));
        }
		
		$this->goBack();
    }


    /**
     * 配置插件变量
     *
     * @param       $pluginName 插件名称
     * @param array $settings 变量键值对
     * @param bool  $isPersonal 是否为私人变量
     */
    public function configPlugin($pluginName, array $settings)
    {
        $pluginName = 'plugin:' . $pluginName;
        $is_option = empty($this->config->$pluginName);

        if (empty($settings)) {
            if (!$is_option) {
                $this->deleteOptions($pluginName);
            }
        } else {
            if ($is_option) {
                $this->addOptions($pluginName, $settings);
            } else {
                $value = Json::decode($this->config->$pluginName);
                $value = array_merge($value, $settings);
                $this->updateOptions($pluginName, $value);
            }
        }
    }

    /**
     * 禁用插件
     *
     * @param $pluginName
     * @throws Exception
     */
    public function deactivate()
    {
		$pluginName = $this->request->filter('strip_tags')->name;
		
        /** 判断是否是已启用的插件 */
        if (!Plugins::exists($pluginName)) {
			throw new Exception(__('无法禁用插件'), 500);
        }
		
		$className = Plugins::getName($pluginName);

        try {
			
			/** 判断插件文件损坏或者被移除 */
            class_exists($className, false) && $result = call_user_func([$className, 'deactivate']);
        } catch (\Exception $e) {
            /** 截获异常 */
            $this->notice($e->getMessage(), 'error');
			
			$this->goBack();
        }

        Plugins::deactivate($pluginName);
		
		/** 更新已启用的插件 */
        $this->updateOptions('plugins', Plugins::export());
		
		/** 删除插件配置 */
        $this->deleteOptions('plugin:' . $pluginName);

        if (isset($result) && is_string($result)) {
            $this->notice($result, 'notice');
        } else {
            $this->notice(__('禁用成功'));
        }
		
		$this->goBack();
    }

    /**
     * 配置外观
     *
     * @access public
     * @param string $theme 外观名
     * @return void
     */
    public function _config()
    {
		$pluginName = $this->request->filter('strip_tags')->name;
		$className = Plugins::getName($pluginName);
		$file      = Plugins::getFile($pluginName);
		
        if(empty($file)){
			$this->notice(__('缺少插件66 %s' .$pluginName, [$pluginName]), 'notice');
			$this->goBack();
		}

        $info = Plugins::getInfo($file);

        /** 判断实例化是否成功 */
        if (!$info['config'] || !Plugins::exists($pluginName)) {
            $this->notice(__('无法配置插件'), 'notice');
			$this->goBack();
        }
		
		$this->parameter->title = __('设置插件 %s', [$pluginName]);
		
		/** 输出内容 */
		$this->layout->set($this->configForm($pluginName, $className), 'body');

		$this->view();
    }


    /**
     * 配置插件
     *
     * @param $pluginName
     * @access public
     * @return void
     */
    public function configSave()
    {
		$pluginName = $this->request->filter('strip_tags')->name;
		$className = Plugins::getName($pluginName);
		$file      = Plugins::getFile($pluginName);

        if(empty($file)){
			$this->notice(__('缺少插件 %s' .$pluginName, [$pluginName]), 'notice');
			$this->goBack();
		}

        $info = Plugins::getInfo($file);

        /** 判断实例化是否成功 */
        if (!$info['config'] || !Plugins::exists($pluginName)) {
            $this->notice(__('无法配置插件'), 'notice');
			$this->goBack();
        }

        $form = $this->configForm($pluginName, $className);

		/** 验证格式 */
        if ($form->validate()) {
            $this->goBack();
        }

        $settings = $form->getAllRequest();

        $this->configPlugin($pluginName, $settings);

        /** 提示信息 */
        $this->notice(__("插件设置已经保存"));
		$this->redirect($this->adminUrl('plugin', false));
    }

    public function configForm($pluginName, $className)
    {
        $form = Html::form();
		$className::config($form);
        $options = \plugin($pluginName);

        if (!empty($options)) {
            foreach ($options as $key => $val) 
			{
                $form->getInput($key)->value($val);
            }
        }

        $submit = Html::submit(__('保存设置'));
        $form->set($submit);
        return $form;
    }
}
